import React, { FC, useEffect, useState, useImperativeHandle, useRef, useMemo } from 'react';
import { ConfigProvider, Transfer, Table, Pagination, Empty } from 'antd';
import { getMessage, TextWidget } from '@inbiz/react';
import './style.less';
import classNames from 'classnames';
import { TransferListBodyProps } from 'antd/lib/transfer/ListBody';
import { TransferItem } from 'antd/lib/transfer';
import { DataType } from '../../../../designer/components/configModal';
import { useRequest } from 'ahooks';
import { useEvents } from '@inbiz/utils';
import { uniqBy, debounce, difference } from 'lodash';
import { apiWrapper, getListData, getTableData } from '../../service';
import { IFieldNames, IReqParams } from '../type';
import {commonLang} from '@inbiz/utils'
import { GlobalRegistry } from '@inbiz/core';
import { IRef, TransferProps } from '../..';
import api from '../../api';
import { useScrollToBottomHook } from '../../../../utils/useScrollToBottom';

interface ICommonProps {
  className?: string;
  fieldOptions: DataType[];
  disabled?: boolean;
  showSearch?:boolean;
  viewMode?:string;
  targetKeys: string[];
}
interface ICustomProps extends ICommonProps {
  dataSource: any[];
  listProps: TransferListBodyProps<TransferItem>;
  rowKey: string;
  viewMode:string;
  showSearch:boolean;
  pagination?: {
    current: number;
    pageSize: number;
    total: number;
  };
  currentPage: number;
  loading: boolean;
  setSelectedKeys: React.Dispatch<React.SetStateAction<string[]>>;
  getDataAsync: (params: { pageIndex: number; pageSize: number, searchValue?:string }) => Promise<any>;
  onScrollToBottom: (direction: 'left' | 'right') => void;
}
interface IProps extends ICommonProps, Pick<TransferProps, 'callBackEvents' | 'emit' | 'onChange'> {
  showPagination?: boolean;
  pageSize: number;
  fieldNames: IFieldNames;
  reqParams: IReqParams;
  viewMode:string;
  showSearch:boolean;
  pRef: IRef;
  modelName: string;
  searchPlaceholder: string;
  disabled:boolean;
}

const CustomComponent: FC<ICustomProps> = ({
  listProps,
  pagination,
  className,
  disabled,
  rowKey,
  viewMode,
  loading,
  targetKeys,
  fieldOptions,
  dataSource,
  currentPage,
  setSelectedKeys,
  getDataAsync,
  onScrollToBottom,
}) => {
  const {
    filteredItems,
    direction,
    onItemSelectAll,
    onItemSelect,
    selectedKeys: listSelectedKeys,
    disabled: listDisabled,
  } = listProps;
  const ref = useRef<any>();
  const cacheCurrentPage = useRef(0);
  useScrollToBottomHook(ref, () => onScrollToBottom(direction));
  const [currentRight, setCurrentRight] = useState(1);
  /**
   * 左侧分页信息变动时拉取接口
   * @param page
   * @param pageSize
   */
  const handleLeftPageChange = (page: number, pageSize: number) => {
    getDataAsync({ pageIndex: page, pageSize });
    setSelectedKeys([]);
  };

  /**
   * 右侧分页信息变动时使用本地数据，不用调用接口
   * @param page
   */
  const handleRightPageChange = (page: number) => {
    setCurrentRight(page);
    setSelectedKeys([]);
  };

  /**
   * antd穿梭框选择
   */
  const rowSelection = {
    getCheckboxProps: (item: any) => ({ disabled: disabled || listDisabled || item.disabled }),
    onSelectAll: (selected: any, selectedRows: any) => {
      const treeSelectedKeys = selectedRows
        .filter((item: any) => !item.disabled)
        .map((i: any) => i[rowKey]);
      const diffKeys = selected
        ? difference(treeSelectedKeys, listSelectedKeys)
        : difference(listSelectedKeys, treeSelectedKeys);
      onItemSelectAll(diffKeys, selected);
    },
    onSelect: (record: any, selected: any) => {
      onItemSelect(record[rowKey], selected);
    },
    selectedRowKeys: listSelectedKeys,
  };

  useEffect(() => {
    if (pagination) {
      const page = Math.ceil(filteredItems.length / pagination.pageSize);
      if (page > 0 && currentRight > page) {
        setCurrentRight(page);
      }
    }
  }, [filteredItems]);

  useEffect(() => {
    if (!pagination) {
      if (ref.current && currentPage === 1 && cacheCurrentPage.current !== currentPage) {
        ref.current.scrollTop = 0;
      }
      cacheCurrentPage.current = currentPage;
    }
  }, [currentPage]); // 防止最大加载后搜索时滚动条始终在底部

  /**
   * 左右穿梭框
   */
  const isNumber = typeof targetKeys[0] === 'number';
  const propertyOption = {
    left: {
      dataSource: dataSource.map((item) => ({
        ...item,
        disabled: targetKeys.includes(isNumber ? item[rowKey] : item[rowKey]?.toString?.()),
      })),
      hasPagination: !!pagination && !!pagination.total,
      pagination: !!pagination && {
        ...pagination,
        onChange: handleLeftPageChange,
      },
    },
    right: {
      dataSource: filteredItems,
      hasPagination: !!pagination && !!filteredItems.length,
      pagination: !!pagination && {
        pageSize: pagination.pageSize,
        total: filteredItems.length,
        current: currentRight,
        onChange: handleRightPageChange,
      },
    },
  }[direction];

  const renderTitle = (title: string) => {
    return title?.indexOf('{multilingual}') >= 0 ? getMessage(title) : title;
  };

  const [locale, $locale] = useState(commonLang[GlobalRegistry.getDesignerLanguage()?.toLocaleLowerCase() as keyof typeof commonLang])
  useEffect(() => {
    $locale(commonLang[GlobalRegistry.getDesignerLanguage()?.toLocaleLowerCase() as keyof typeof commonLang])
  }, [GlobalRegistry.getDesignerLanguage()]);
  return (
    <section
      className={`${className}-customList`}
      style={{ overflow: propertyOption['pagination'] ? 'hidden' : 'auto' }}
    >
      <ConfigProvider locale={locale}>
        <Table
          ref={ref}
          disabled
          showHeader={fieldOptions.length > 1}
          rowKey={(record) => record[rowKey]}
          className={classNames(`${className}-table`, {
            [`${className}-pagination-table`]: propertyOption['hasPagination'],
          })}
          rowSelection={rowSelection}
          columns={fieldOptions.map((item) => ({
            dataIndex: item.field,
            title: renderTitle(item.label ? item.label : item.field),
            ellipsis:true
          }))}
          dataSource={propertyOption['dataSource']}
          size="small"
          onRow={(record) => ({
            onClick: () => {
              if (record.disabled || listDisabled) return;
              onItemSelect(record[rowKey], !listSelectedKeys.includes(record[rowKey]));
            },
          })}
          locale={{
            emptyText: (
              <Empty
                image={Empty.PRESENTED_IMAGE_SIMPLE}
                description={<TextWidget>Transfer.no_data</TextWidget>}
              />
            ),
          }}
          loading={direction === 'left' && loading}
          pagination={direction === 'left' ? false : propertyOption['pagination']}
        />
        {propertyOption['hasPagination'] && (
          <Pagination
            className={`${className}-pagination`}
            simple
            {...propertyOption['pagination']}
          />
        )}
      </ConfigProvider>
    </section>
  );
};

interface IState {
  searchValue: string;
  dataSource: any[];
  totalDataSource: any[];
  searchDataSource: any[];
  pagination: {
    current: number;
    pageSize: number;
    total: number;
  };
}

const TableTransfer: FC<IProps> = (props) => {
  const {
    targetKeys,
    showPagination,
    pageSize,
    className,
    fieldNames,
    disabled,
    viewMode,
    showSearch,
    fieldOptions,
    reqParams,
    onChange: onChangeProps,
    callBackEvents,
    emit,
    pRef,
    modelName,
    ...restProps
  } = props;
  const [configEvents] = useEvents(callBackEvents, emit);

  const [state, setState] = useState<IState>({
    searchValue: '',
    dataSource: [],
    totalDataSource: [],
    searchDataSource: [],
    pagination: {
      current: 1,
      pageSize: pageSize || 10,
      total: 0,
    },
  });
  const selectDataRef = useRef<object[]>([]);
  const [selectedKeys, setSelectedKeys] = useState<string[]>([]);

  const [load, setLoad] = useState(false);

  /**
   *  扩展代码相关包装
   */
  const getDataService = apiWrapper(getTableData, configEvents, {
    onRequest: 'onRequest',
    onParamFormat: 'onParamFormat',
    onData: 'onData',
  });

  const { runAsync: getDataAsync, loading } = useRequest(
    (paramsTemp) => {
      let params = { ...paramsTemp };
      const args = Object.assign(
        reqParams,
        params.searchValue || state.searchValue?.trim()
          ? {
              searchValue: state.searchValue?.trim(),
              searchKey: fieldNames['searchKey'],
              ...params,
            }
          : params,
      );
      return getDataService(args);
    },
    {
      defaultParams: [{ pageIndex: 1, pageSize } as { pageIndex: number; pageSize: number; searchValue?: string }],
      onSuccess: (res: any, params: any) => {
        /**
         * 针对左侧数据变动（如分页，搜索，滚动加载）需要对数据源做不同设置，分为搜索数据：searchDataSource，表格数据：dataSource，总数据：totalDataSource
         * 情况1、存在分页时 dataSource 就使用远端数据即可
         * 情况2、不存在分页（滚动加载）但是在第一页时 dataSource 也使用远端数据
         * 情况3、不存在分页（滚动加载）且页码大于 1 （滚动一次加一页数据）时，dataSource 的数据应该叠加之前的数据
         *
         * 以上 3 种情况对于搜索来说是另一条独立分支，完全适用，所以 searchDataSource 也需要做类似逻辑，要注意考虑存在数据时搜索、和搜索完返回后 dataSource 和 searchDataSource 的变化
         */
        setState((prev) => {
          res.data = res.data.map((item: any) => {
            return {
              ...item,
              id: item.id?.toString?.(),
            };
          });
          let nextDataSource: any[] = [];
          if (showPagination) {
            nextDataSource = uniqBy(res.data, fieldNames['key']);
          } else if (params[0].pageIndex > 1) {
            nextDataSource = uniqBy(prev.dataSource.concat(res.data), fieldNames['key']);
          } else {
            nextDataSource = uniqBy(res.data, fieldNames['key']);
          }
          let nextSearchDataSource: any[] = [];
          if (!params[0].searchValue) {
            nextSearchDataSource = [];
          } else if (params[0].pageIndex > 1) {
            nextSearchDataSource = uniqBy(
              prev.searchDataSource.concat(res.data),
              fieldNames['key'],
            );
          } else {
            nextSearchDataSource = uniqBy(res.data, fieldNames['key']);
          }
          const nextTotalDataSource = uniqBy(
            prev.totalDataSource.concat(res.data),
            fieldNames['key'],
          );
          return {
            searchValue: params[0].searchValue?.trim() || '',
            pagination: {
              ...prev.pagination,
              total: res.totalCount,
              pageSize: params[0].pageSize,
              current:
                showPagination || res.data?.length ? params[0].pageIndex : prev.pagination.current, // 没有分页时，拉取最新页没有数据的时候不应该继续拉取了
            },
            dataSource: nextDataSource,
            totalDataSource: nextTotalDataSource,
            searchDataSource: nextSearchDataSource,
          };
        });
        if (!load) {
          setLoad(true);
        }
        emit?.('onSuccess', res);
      },
      onError: () => emit?.('onError'),
    },
  );

  /**
   * 左侧搜索，需要异步拉取接口，同时做防抖处理
   */
  const handleLeftSearch = debounce((direction: 'left' | 'right', searchValue: string) => {
    if (direction === 'left') {
      setSelectedKeys([]);
      getDataAsync({
        searchValue: searchValue?.trim(),
        pageIndex: 1,
        pageSize: state.pagination.pageSize,
      });
    }
  }, 300);

  /**
   * 左侧滚动到底部需要异步拉取数据
   * @param directiong
   */
  const onScrollToBottom = (direction: 'left' | 'right') => {
    const hasData =
      state.pagination.total >
      uniqBy(state.dataSource.concat(state.searchDataSource), fieldNames['key']).length;
    if (direction === 'left' && !showPagination && hasData) {
      getDataAsync({
        searchValue: state.searchValue?.trim(),
        pageSize: state.pagination.pageSize,
        pageIndex: state.pagination.current + 1,
      });
    }
  };

  const onChange = (v: string[], b, c) => {
    onChangeProps?.(v);
    setSelectedKeys([]);
    emit?.(
      'onSelect',
      v,
      state.totalDataSource.filter((item) => v.includes(item[fieldNames.key])),
    );
  };

  const onSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
    setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
    emit?.('onSelectChange', sourceSelectedKeys, targetSelectedKeys);
  };

  /**
   * 对于数据回显时需要根据 id 拉取详细的数据用于右侧显示
   * @param ids 已选的条目 id 数组
   */
  const getSelectedList = async (ids: string[]) => {
    try {
      const totalKey = state.totalDataSource.map((item) => item[fieldNames.key]);
      if (ids.length > 0 && ids.some((key) => !totalKey.includes(key))) {
        const res = await getListData({
          appId: reqParams.appId,
          ids: ids,
          key: reqParams.sourceKey,
          field: fieldNames['key'],
          modelName,
        });
        setState((prev) => ({
          ...prev,
          totalDataSource: uniqBy(prev.totalDataSource.concat(res), fieldNames['key']),
        }));
      }
    } catch (e) {
      console.log(e);
    }
  };

  useImperativeHandle(
    pRef,
    () => ({
      ...api(configEvents, {
        ...props,
        setState: (v: any[]) =>
          setState((prev) => ({ ...prev, dataSource: v, totalDataSource: v })),
        onChange,
        targetKeys,
        dataSource: state.dataSource,
        fieldNames,
        selectDataRef,
      }),
    }),
    [state, fieldNames, targetKeys],
  );

  useEffect(() => {
    if (typeof pageSize === 'number') {
      setState((prev) => ({ ...prev, pagination: { ...prev.pagination, pageSize } }));
    }
  }, [pageSize]);

  useEffect(() => {
    if (load) {
      emit?.('onload');
    }
  }, [load]);

  useEffect(() => {
    getSelectedList(targetKeys);
  }, [targetKeys]);
  return (
    <Transfer
      {...restProps}
      selectedKeys={selectedKeys}
      targetKeys={targetKeys}
      rowKey={(record) => record[fieldNames.key]}
      className={className}
      disabled={viewMode=='look'?true:disabled}
      dataSource={uniqBy(
        state.totalDataSource
          .filter((item) => targetKeys.includes(item[fieldNames['key']]))
          .concat(state.dataSource)
          .concat(state.searchDataSource),
        fieldNames['key'],
      )}
      locale={{
        notFoundContent: (
          <Empty
            image={Empty.PRESENTED_IMAGE_SIMPLE}
            description={<TextWidget>Transfer.no_data</TextWidget>}
          />
        ),
        searchPlaceholder: props.searchPlaceholder,
      }}
      filterOption={(inputValue, item) => {
        // 指定的搜索字段进行搜索
        return (
          String(item[fieldNames.searchKey]).toLowerCase().indexOf(inputValue.toLowerCase()) !== -1
        );
        // 所有的字段进行搜索
        // return fieldOptions.some(
        //   (field) =>{
        //     // return String(item[field['field']]).toLowerCase().indexOf(inputValue.toLowerCase()) !== -1
        //   }
        // );
      }}
      onSearch={handleLeftSearch}
      showSearch={viewMode=='look'?false:showSearch}
      onSelectChange={disabled ? undefined : onSelectChange}
      onChange={onChange}
      selectAllLabels={[
        ({ selectedCount }) => `${selectedCount}/${state.pagination.total || 0}`,
        ({ selectedCount, totalCount }) => `${selectedCount}/${totalCount}`,
      ]}
      showSelectAll={!disabled}
    >
      {(listProps) => {
        selectDataRef.current = listProps.filteredItems;
        return (
          <CustomComponent
            currentPage={state.pagination.current}
            onScrollToBottom={onScrollToBottom}
            getDataAsync={getDataAsync}
            rowKey={fieldNames.key || 'key'}
            targetKeys={targetKeys} // 表格的 dataSource 主要用于独立控制左侧，右侧的显示通过 Transfer 的 dataSource 和 filterOption 控制（需要做穿梭框内部的前端搜索等）
            dataSource={state.dataSource}
            loading={loading}
            disabled={disabled}
            listProps={listProps}
            className={className}
            fieldOptions={fieldOptions}
            setSelectedKeys={setSelectedKeys}
            viewMode={viewMode}
            {...Object.assign({}, showPagination ? { pagination: state.pagination } : {})}
          />
        );
      }}
    </Transfer>
  );
};

export default TableTransfer;
